using System;
using UnityEngine;

namespace AGame.TabOrm.TabOrmAttributeExpand
{
    public class UnityTabField : TabField
    {
        private readonly char _separator;
        private readonly bool _hasBracket;

        public UnityTabField(char separator = ',', bool hasBracket = true)
        {
            _separator = separator;
            _hasBracket = hasBracket;
        }

        public override Func<string, object> GetStrToObjFunc(Type tabType, Type targetType)
        {
            if (targetType == typeof(Vector2))
            {
                return Vector2StrToObj;
            }

            if (targetType == typeof(Vector3))
            {
                return Vector3StrToObj;
            }

            if (targetType == typeof(Rect))
            {
                return RectStrToObj;
            }

            if (targetType == typeof(Color))
            {
                return ColorStrToObj;
            }

            return null;
        }

        public override Func<object, string> GetObjToStrFunc(Type tabType, Type targetType)
        {
            if (targetType == typeof(Vector2))
            {
                return Vector2ObjToStr;
            }

            if (targetType == typeof(Vector3))
            {
                return Vector3ObjToStr;
            }

            if (targetType == typeof(Rect))
            {
                return RectObjToStr;
            }

            if (targetType == typeof(Color))
            {
                return ColorObjToStr;
            }

            return null;
        }

        private object Vector2StrToObj(string str)
        {
            StringToFloatArray(str, out var x, out var y, out _, out _);
            return new Vector2(x, y);
        }

        private object Vector3StrToObj(string str)
        {
            StringToFloatArray(str, out var x, out var y, out var z, out _);
            return new Vector3(x, y, z);
        }

        private object RectStrToObj(string str)
        {
            StringToFloatArray(str, out var x, out var y, out var width, out var height);
            return new Rect(x, y, width, height);
        }

        private object ColorStrToObj(string str)
        {
            StringToFloatArray(str, out var r, out var g, out var b, out var a, 1, 1, 1, 1);
            return new Color(r, g, b, a);
        }

        private string Vector2ObjToStr(object obj)
        {
            if (obj is Vector2 vector2)
            {
                return _hasBracket ? $"({vector2.x}{_separator}{vector2.y})" : $"{vector2.x}{_separator}{vector2.y}";
            }

            return string.Empty;
        }

        private string Vector3ObjToStr(object obj)
        {
            if (obj is Vector3 rect)
            {
                return _hasBracket
                    ? $"({rect.x}{_separator}{rect.y}{_separator}{rect.z})"
                    : $"{rect.x}{_separator}{rect.y}{_separator}{rect.z}";
            }

            return string.Empty;
        }

        private string RectObjToStr(object obj)
        {
            if (obj is Rect rect)
            {
                return _hasBracket
                    ? $"({rect.x}{_separator}{rect.y}{_separator}{rect.width}{_separator}{rect.height})"
                    : $"{rect.x}{_separator}{rect.y}{_separator}{rect.width}{_separator}{rect.height}";
            }

            return string.Empty;
        }

        private string ColorObjToStr(object obj)
        {
            if (obj is Color color)
            {
                return _hasBracket
                    ? $"({color.r}{_separator}{color.g}{_separator}{color.b}{_separator}{color.a})"
                    : $"{color.r}{_separator}{color.g}{_separator}{color.b}{_separator}{color.a}";
            }

            return string.Empty;
        }

        private void StringToFloatArray(string str, out float num1, out float num2, out float num3, out float num4,
            float num1default = 0, float num2default = 0, float num3default = 0, float num4default = 0)
        {
            str = str.Trim();
            if (string.IsNullOrEmpty(str))
            {
                num1 = num1default;
                num2 = num2default;
                num3 = num3default;
                num4 = num4default;
                return;
            }

            if (_hasBracket && str.Length >= 2)
            {
                str = str.Substring(1, str.Length - 2);
            }

            var split = str.Split(_separator);
            if (split.Length <= 0 || !float.TryParse(split[0], out num1))
            {
                num1 = num1default;
            }

            if (split.Length <= 1 || !float.TryParse(split[1], out num2))
            {
                num2 = num2default;
            }

            if (split.Length <= 2 || !float.TryParse(split[2], out num3))
            {
                num3 = num3default;
            }

            if (split.Length <= 3 || !float.TryParse(split[3], out num4))
            {
                num4 = num4default;
            }
        }
    }
}